跳到主要内容

08 - 集合TSet

本文主要说明了UE5中有关容器类集合TSet的相关概念和常见操作。

TSet

TSet 是一种快速容器类,用于在排序不重要的情况下存储唯一元素。在大多数情况下,只需要一种参数——元素类型。

TSet 使用哈希,即如果给出了 KeyFuncs 模板参数,该参数会告知集合如何从某个元素确定键,如何比较两个键是否相等,如何对键进行哈希,以及是否允许重复键。它们默认只返回对键的引用,使用 operator== 对比相等性,使用非成员函数 GetTypeHash() 进行散列。默认情况下,集合中不允许有重复的键。如果您的键类型支持这些函数,则可以将其用作集合键,无需提供自定义 KeyFuncs。要写入自定义 KeyFuncs,需要继承 DefaultKeyFuncs 结构体。

此外,内存中 TSet 元素的相对排序既不可靠也不稳定,对这些元素进行迭代很可能会使它们返回的顺序和它们添加的顺序有所不同。这些元素也不太可能在内存中连续排列。

声明

TSet的创建方法如下:

TSet<FString> FruitSet;

添加元素

可用Add()Emplace()添加单个元素,用Append()进行合并来插入另一个集合中的所有元素。

遍历元素

TSet支持基于范围和基于迭代器的遍历:

// 基于范围的遍历
for (auto& Elem : FruitSet)
{
FPlatformMisc::LocalPrint(
*FString::Printf(
TEXT(" \"%s\"\n"),
*Elem
)
);
}

// 基于迭代器的遍历
for (auto It = FruitSet.CreateConstIterator(); It; ++It)
{
FPlatformMisc::LocalPrint(
*FString::Printf(
TEXT("(%s)\n"),
*It
)
);
}

排序

如果此后不再对TSet增删元素,那么就能用Sort()进行排序:

FruitSet.Sort([](const FString& A, const FString& B) {
return A > B; // 逆字典序
});

FruitSet.Sort([](const FString& A, const FString& B) {
return A.Len() < B.Len(); // 字符串长度从小到大
});

查询

TSet同样提供了一系列查询函数,供用户调用:

函数说明
Num()获取集合中元素个数
Contains()确认集合是否包含特定元素
Index()查询集合中是否包含特定元素,返回索引结构体FSetElementId
Find()查询集合中是否包含特定元素,并返回指向元素的指针
Array()TArray形式返回TSet所有元素的副本

移除

可通过Remove()移除指定元素,并返回移除元素的个数。也能使用Empty()Reset()清空集合元素,区别是处理Slack的方式不同。

运算符

TSet支持通过operator=直接将集合A的值拷贝给集合B。

Slack

TSet支持通过Reserve()Reset()Empty()管理Slack,使用方式同其他两个容器类。

此外和TMap类似,在删除元素后处理多余Slack时,需要先调用Compact()CompactStable()整理空白空间(后者在合并空元素时保持它们的排序),再使用Shrink()删除末尾的Slack

编写KeyFuncs

如果要将自定义类型应用到TSet中,就需要基于DefaultKeyFuncs编写KeyFuncs。和TMap类似,需要定义两个typedef和三个静态函数:

  • KeyInitType:用于传递键的类型,通常为ElementType模板参数;
  • ElementInitType:用于传递元素的类型,通常也是ElementType模板参数;
  • KeyInitType GetKey(ElementInitType Element):返回元素的键,通常是集合元素本身;
  • bool Matches(KeyInitType A, KeyInitType B)AB 是否相等;
  • uint32 GetKeyHash(KeyInitType Key):返回键的哈希值。

参考资料